﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using PenguinForce.Behaviors;
using System;
using PenguinForce.Entities;
using Microsoft.Xna.Framework.Content;
using System.Collections.Generic;

namespace PenguinForce.Entities
{
    /// <summary>
    /// A simple object that moves towards it's set destination
    /// </summary>
    public class FlockMaster : Entity // DrawableGameComponent
    {
        #region Constants

        /// <summary>
        /// The "close enough" limit, if the tank is inside this many pixel 
        /// to it's destination it's considered at it's destination
        /// </summary>
        private const float DESTINATION_LIMIT = 1f;

        private const float MAX_MOVE_SPEED = 90f;

        private const float MAX_ANGULAR_VELOCITY = MathHelper.Pi;

        private const float MAX_MOVE_SPEED_DELTA = MAX_MOVE_SPEED / 2;

        #endregion

        #region Variables

        /// <summary>
        /// The tanks’ current movement behavior, it’s responsible for updating the 
        /// tanks’ movement speed and direction
        /// </summary>
        private Behavior _currentBehavior;

        private BehaviorType _behaviorType;

        private WaypointList _waypoints;

        #endregion

        #region Constructors

        /// <summary>
        /// Tank constructor
        /// </summary>
        public FlockMaster(ContentManager content)
            : base(null)
        {
            _location = Vector2.Zero;
            _waypoints = new WaypointList();
            BehaviorType = BehaviorType.Linear; //.Steering;
            _animaltype = EntityType.Tank;
        }

        #endregion

        #region Properties

        /// <summary>
        /// This is how much the Tank can turn in one second in radians, since Pi 
        /// radians makes half a circle the tank can all the way around in one second
        /// </summary>
        public static float MaxAngularVelocity
        {
            get
            {
                return MAX_ANGULAR_VELOCITY;
            }
        }

        /// <summary>
        /// This is the Tanks’ best possible movement speed
        /// </summary>
        public static float MaxMoveSpeed
        {
            get
            {
                return MAX_MOVE_SPEED;
            }
        }

        /// <summary>
        /// This is most the tank can speed up or slow down in one second
        /// </summary>
        public static float MaxMoveSpeedDelta
        {
            get
            {
                return MAX_MOVE_SPEED_DELTA;
            }
        }

        /// <summary>
        /// Gets the current movement behavior
        /// </summary>
        public BehaviorType BehaviorType
        {
            get
            {
                return _behaviorType;
            }
            set
            {
                if ((_behaviorType != value) || (_currentBehavior == null))
                {
                    _behaviorType = value;
                    switch (_behaviorType)
                    {
                        case BehaviorType.Linear:
                            _currentBehavior = new LinearBehavior(this);
                            break;
                        case BehaviorType.Steering:
                            _currentBehavior = new SteeringBehavior(this);
                            break;
                        default:
                            break;
                    }
                }
            }
        }

        /// <summary>
        /// The tank's current movement speed
        /// </summary>
        public float MoveSpeed
        {
            get
            {
                return _moveSpeed;
            }
            set
            {
                _moveSpeed = value;
            }
        }

        /// <summary>
        /// The list of points the tanks will move to in order from first to last
        /// </summary>
        public WaypointList Waypoints
        {
            get
            {
                return _waypoints;
            }
        }

        /// <summary>
        /// Linear distance to the Tank's current destination
        /// </summary>
        public float DistanceToDestination
        {
            get
            {
                return Vector2.Distance(_location, _waypoints.Peek());
            }
        }

        /// <summary>
        /// True when the tank is "close enough" to it's destination
        /// </summary>
        public bool AtDestination
        {
            get
            {
                return DistanceToDestination < DESTINATION_LIMIT;
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Load the tank's texture resources
        /// </summary>
        /// <param name="content"></param>
        public void LoadContent(ContentManager content)
        {
            _waypoints.LoadContent(content);
        }

        /// <summary>
        /// Reset the Tank's location on the map
        /// </summary>
        /// <param name="newLocation">new location on the map</param>
        public void Reset(Vector2 newLocation)
        {
            _location = newLocation;
            this.Reset();
        }

        public void Reset()
        {
            _waypoints.Clear();
        }

        /// <summary>
        /// Update the Tank's position if it's not "close enough" to 
        /// it's destination
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds;

            // If we have any waypoints, the first one on the list is where 
            // we want to go
            if (_waypoints.Count > 0)
            {
                if (AtDestination)
                {
                    // If we’re at the destination and there is at least one 
                    // waypoint in the list, get rid of the first one since we’re 
                    // there now
                    _waypoints.Dequeue();
                }
                else
                {
                    // If we’re not at the destination, call Update on our 
                    // behavior and then move
                    if (_currentBehavior != null)
                    {
                        _currentBehavior.Update(gameTime);
                    }
                    _location = _location + (Direction * MoveSpeed * elapsedTime);
                }
            }
        }

        /// <summary>
        /// Draw the Tank
        /// </summary>
        /// <param name="gameTime"></param>
        /// <param name="spriteBatch"></param>
        public override void Draw(SpriteBatch spriteBatch, GameTime gameTime)
        {
            _waypoints.Draw(spriteBatch);
            //base.Draw(spriteBatch, gameTime);
        }

        /// <summary>
        /// Change the tank movement Behavior
        /// </summary>
        public void CycleBehaviorType()
        {
            switch (_behaviorType)
            {
                case BehaviorType.Linear:
                    BehaviorType = BehaviorType.Steering;
                    break;
                case BehaviorType.Steering:
                default:
                    BehaviorType = BehaviorType.Linear;
                    break;
            }
        }

        #endregion
    }
}